home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’96 / FinderFlocks / CFlock.cp < prev    next >
Encoding:
Text File  |  1996-06-23  |  9.0 KB  |  353 lines  |  [TEXT/CWIE]

  1. #include "CFlock.h"
  2. #include "FlockDrawing.h"
  3.  
  4. // a sick hack for key control of the flock
  5. ControlRec            gCurrentControls;
  6. Boolean                gControlsChanged;
  7. long                timer;
  8.  
  9. extern long                gNumItems;
  10. extern Handle            gIcons[];
  11. extern Handle            gMasks[];
  12. extern Point            gPositions[];
  13.  
  14. CFlock::CFlock(void)
  15. {
  16.     short    cnt;
  17.     
  18.     for(cnt = 0; cnt < kMaxBoids; cnt++)
  19.         fTheBoids[cnt] = nil;    // array of boids
  20. }
  21.  
  22. CFlock::~CFlock(void)
  23. {
  24. }
  25.  
  26. CFlock* CFlock :: InitFlock(RgnHandle blankRgn)
  27. {
  28.     short        cnt;
  29.     Handle        hVals;    
  30.     
  31.     HLock((Handle)this);
  32.     
  33.     /* Get the controls from the FCTL resource for this flock type */
  34.     this->fControls.fNumBoidsCtl = gNumItems;
  35.     
  36.     // •• leftovers
  37.     this->fControls.fBoidTypeCtl = 8;
  38.     GetNewControls(&this->fControls, this->fControls.fBoidTypeCtl);
  39.     this->fControls.fMaxVelocityCtl = 0;
  40.     this->fControls.fMaxAccelCtl = 0;
  41.  
  42.     // !!! stash them everywhere
  43.     this->fGoodControls = gCurrentControls = this->fControls;
  44.     
  45.     // set correct screen rect
  46.     this->fMasterFlockRect = (**blankRgn).rgnBBox;
  47.     
  48.     /* Set up some fields in the flock structure for easy reference */
  49.     this->fNumBoids = fGoodControls.fNumBoidsCtl;
  50.     this->fMaxEffort = fGoodControls.fMaxEffortCtl;
  51.     
  52.     /* Adjust the flockrect to the boid size */
  53.     this->fFlockRect = this->fMasterFlockRect;
  54.     this->fFlockRect.right -= 32; // !•
  55.     this->fFlockRect.bottom -= 32;// !•
  56.  
  57.     /* Do the Aware distance processing */
  58.     this->fAwareDist = this->fGoodControls.fAwareDistCtl;
  59.     this->fAwareDistSquared = this->fAwareDist * this->fAwareDist;
  60.     
  61.     /* Do the comfy distance processing */
  62.     this->fComfyDist = this->fGoodControls.fComfyDistCtl;    
  63.     this->fComfyDistSquared = this->fComfyDist * this->fComfyDist;
  64.     
  65.     // Now init a boid for each item
  66.     for (cnt = 0; cnt < this->fNumBoids; cnt++)
  67.     {
  68.         fTheBoids[cnt] = ((CBoid *)new(CBoid))->InitBoid(&this->fFlockRect,
  69.                             gIcons[cnt], gMasks[cnt], gPositions[cnt]);
  70.         
  71.         if(fTheBoids[cnt] == nil)
  72.         {
  73.             short donecount;
  74.             Str255    errstr;
  75.  
  76.             // Kill the boids already inited
  77.             for(donecount = 0; donecount < cnt; donecount++)
  78.                 delete(fTheBoids[donecount]);
  79.             
  80.             HUnlock((Handle)this);
  81.             return nil;
  82.         }
  83.     }
  84.     
  85.     // Made it!
  86.     HUnlock((Handle)this);
  87.     
  88.     //Start with zero velocity
  89.     timer = TickCount();
  90.     return(this);
  91. }
  92.  
  93. OSErr CFlock :: FlockStep(RgnHandle blankRgn)
  94. {
  95.     short        cnt, rand, err;
  96.     FloatPoint    dummy;
  97.     
  98.     // Ramp up at the start
  99.     if(gCurrentControls.fMaxVelocityCtl == 0)
  100.     {
  101.         if(TickCount() - timer > 180)
  102.         {
  103.             gCurrentControls.fMaxVelocityCtl = 1;
  104.             gCurrentControls.fMaxAccelCtl = 1;
  105.             this->ControlsChanged(&gCurrentControls, blankRgn);
  106.             timer = TickCount();
  107.         }
  108.     }
  109.     else if(TickCount() - timer > 60 && gCurrentControls.fMaxAccelCtl < 5)
  110.     {
  111.         gCurrentControls.fMaxVelocityCtl += 2;
  112.         gCurrentControls.fMaxAccelCtl += 1;
  113.         timer = TickCount();
  114.         this->ControlsChanged(&gCurrentControls, blankRgn);
  115.     }
  116.     
  117.     // Set the port to sprocket context
  118.     err = StartDrawing();
  119.     if(err) return err;
  120.     
  121.     // if fNumBoids > zero and no error, continue
  122.     if( (fNumBoids > 0) && (err == noErr) )
  123.     {
  124.         // Here's where the NeighborRecords get filled in
  125.         this->FindNeighbors();    
  126.     
  127.         // Now that the Neighbors are all recorded, we can move each boid    
  128.         for(cnt = 0; cnt < fNumBoids; cnt++)
  129.         {
  130.             this->fTheBoids[cnt]->Move(
  131.                                         &dummy,
  132.                                         &this->fFlockRect,
  133.                                         &this->fGoodControls,
  134.                                         this->fComfyDistSquared );
  135.         }
  136.     }
  137.     
  138.     // Draw the control values, too
  139.     //DrawControlValues(&this->fMasterFlockRect);
  140.     
  141.     // Done drawing
  142.     err = EndDrawing();
  143.     
  144.     return err;
  145. }
  146.  
  147. void CFlock::ShakeFlock(void)
  148. {
  149.     // Randomize directions for a few frames
  150. }
  151.  
  152. void CFlock::KillFlock(RgnHandle blankRgn)
  153. {
  154.     short        cnt;
  155.     
  156.     // Fly home
  157.     this->FlyHome(blankRgn);
  158.     
  159.     // Kill all the boids
  160.     for (cnt = 0; cnt < kMaxBoids; cnt++)
  161.     {
  162.         delete(this->fTheBoids[cnt]);
  163.         fTheBoids[cnt] = nil;
  164.     }
  165. }
  166.  
  167. // This routine processes the raw (0 - 100) controls into good
  168. // ones, and changes some stuff accordingly
  169. OSErr CFlock :: ControlsChanged(ControlRec *newControls, RgnHandle blankRgn)
  170. {
  171.     OSErr    err = noErr;
  172.     
  173.     StartDrawing(); // in case of erasing or redrawing
  174.     
  175.     // !!! Should remove fGoodControls, not needed any more (maybe)
  176.     this->fGoodControls = this->fControls = *newControls;
  177.     
  178.     // If the comfy distance has changed, deal with it
  179.     if(this->fGoodControls.fComfyDistCtl != this->fComfyDist)
  180.     {
  181.         this->fComfyDist = this->fGoodControls.fComfyDistCtl;
  182.         this->fComfyDistSquared = this->fComfyDist * this->fComfyDist;
  183.     }
  184.  
  185.     // If the AwareDist has changed, deal with it
  186.     if(this->fGoodControls.fAwareDistCtl != this->fAwareDist)
  187.     {
  188.         this->fAwareDist = this->fGoodControls.fAwareDistCtl;
  189.         this->fAwareDistSquared = this->fAwareDist * this->fAwareDist;
  190.     }
  191.     
  192.     // Swap Buffers in case there was drawing (or erasing
  193.     err = EndDrawing();
  194.     
  195.     return err;
  196. }
  197.  
  198.  
  199. void CFlock :: FindNeighbors(void)
  200. {
  201.     CBoid        **thisboid, **thatboid, **lastboid;
  202.     double        dist;
  203.     FloatPoint    thisPos, thatPos, thisVel, thatVel;
  204.     
  205.     // Set up
  206.     thisboid = &fTheBoids[0];
  207.     lastboid = &fTheBoids[fNumBoids - 1];
  208.     dist = this->fAwareDist;
  209.  
  210.  
  211.     do        // for all boids
  212.     {
  213.         if(thisboid == lastboid)    // To prevent an endless loop
  214.             continue;
  215.         thatboid = thisboid;
  216.         (*thisboid)->GetBoidPos(&thisPos);
  217.         (*thisboid)->GetBoidVel(&thisVel);
  218.         
  219.         // This loop looks at each boid "below" thisboid in the list
  220.         while(thatboid++ != lastboid)
  221.         {
  222.             double    sqdist;
  223.             double    diffh, diffv;
  224.             
  225.             (*thatboid)->GetBoidPos(&thatPos);
  226.             
  227.             // Check, x, then y
  228.             diffh = thatPos.h - thisPos.h;
  229.             if(fabs(diffh) > dist)
  230.                 continue;
  231.                 
  232.             diffv = thatPos.v - thisPos.v;
  233.             if(fabs(diffv) > dist)
  234.                 continue;
  235.  
  236.             // Compute the distance squared between this pair of boids
  237.             sqdist = VecMagSq(diffh, diffv);
  238.             
  239.             // If close enough, add to neighbors of both boids    
  240.             if(sqdist < this->fAwareDistSquared)
  241.             {
  242.                 // Get the velocity of that boid, now that we know we'll need it
  243.                 (*thatboid)->GetBoidVel(&thatVel);
  244.                 
  245.                 // -----------------------
  246.                  // Look from this to that
  247.                 // -----------------------
  248.                 if((*thisboid)->fNaybs.fNum == 0) // First neighbor for this boid
  249.                 {
  250.                     (*thisboid)->fNaybs.fAvgPos = thatPos;
  251.                     (*thisboid)->fNaybs.fAvgVel = thatVel;
  252.                 }
  253.                 else    // Average in this neighbor with the others
  254.                 {
  255.                     TwoVecAvg(&((*thisboid)->fNaybs.fAvgPos), &thatPos);
  256.                     TwoVecAvg(&((*thisboid)->fNaybs.fAvgVel), &thatVel);
  257.                 }
  258.                 // the neighbors' average distance is the difference between thisPos
  259.                 // and the average position
  260.                 (*thisboid)->fNaybs.fAvgDistSquared = 
  261.                     VecMagSq(    thisPos.h - ((*thisboid)->fNaybs.fAvgPos).h, 
  262.                                 thisPos.v - ((*thisboid)->fNaybs.fAvgPos).v        );
  263.                 
  264.                 // if the distance between these boids is less than the nearest neighbor,
  265.                 // then thatboid is our new nearest neighbor
  266.                 if(sqdist < (*thisboid)->fNaybs.fNearestDistSquared)
  267.                 {
  268.                     (*thisboid)->fNaybs.fNearestDistSquared = sqdist;
  269.                     (*thisboid)->fNaybs.fNearestPos = thatPos;
  270.                 }
  271.  
  272.                 // Remember to increment number of neighbors
  273.                 (*thisboid)->fNaybs.fNum++;
  274.  
  275.                 // -----------------------
  276.                 // Look from that to this
  277.                 // -----------------------
  278.                 if((*thatboid)->fNaybs.fNum == 0) // First neighbor for that boid
  279.                 {
  280.                     ((*thatboid)->fNaybs.fAvgPos) = thisPos;
  281.                     ((*thatboid)->fNaybs.fAvgVel) = thisVel;
  282.                 }
  283.                 else    // Average in this neighbor with the others
  284.                 {
  285.                     TwoVecAvg(&((*thatboid)->fNaybs.fAvgPos), &thisPos);
  286.                     TwoVecAvg(&((*thatboid)->fNaybs.fAvgVel), &thisVel);
  287.                 }
  288.                 // the neighbors' average distance is the difference between thatPos
  289.                 // and the average position
  290.                 (*thatboid)->fNaybs.fAvgDistSquared = 
  291.                     VecMagSq(    thatPos.h - ((*thatboid)->fNaybs.fAvgPos).h, 
  292.                                 thatPos.v - ((*thatboid)->fNaybs.fAvgPos).v        );
  293.  
  294.                 // if the distance between these boids is less than the nearest neighbor,
  295.                 // then thisboid is our new nearest neighbor
  296.                 if(sqdist < (*thatboid)->fNaybs.fNearestDistSquared)
  297.                 {
  298.                     (*thatboid)->fNaybs.fNearestDistSquared = sqdist;
  299.                     (*thatboid)->fNaybs.fNearestPos = thisPos;
  300.                 }
  301.                 
  302.                 // Remember to increment number of neighbors
  303.                 (*thatboid)->fNaybs.fNum++;
  304.  
  305.             } // if in range
  306.         } // while
  307.     }while(thisboid++ != lastboid);
  308. }
  309.  
  310. void CFlock :: FlyHome(RgnHandle blankRgn)
  311. {
  312.     short        cnt, cnt2;
  313.     FloatPoint    dummy;
  314.     Boolean        done = false;
  315.     long        ticks;
  316.     
  317.     // Set the controls to center only
  318.     gCurrentControls.fAwareDistCtl = 20000;
  319.     gCurrentControls.fComfyDistCtl = 1;
  320.     gCurrentControls.fAvoidMaxCtl = 0;
  321.     gCurrentControls.fMatchMaxCtl = 0;
  322.     gCurrentControls.fCenterMaxCtl = 10;
  323.     gCurrentControls.fMaxEffortCtl = 10;
  324.     gCurrentControls.fMaxAccelCtl = 2;
  325.     gCurrentControls.fMaxVelocityCtl = 5;
  326.     this->ControlsChanged(&gCurrentControls, blankRgn);
  327.     
  328.     // go home
  329.     ticks = TickCount();
  330.     while(!done)
  331.     {
  332.         done = true;
  333.         StartDrawing();
  334.         for(cnt = 0; cnt < fNumBoids; cnt++)
  335.         {
  336.             if(!this->fTheBoids[cnt]->HeadHome()) // if anyone's not home yet, keep going
  337.             {
  338.                 if(TickCount() - ticks > 600)
  339.                     this->fTheBoids[cnt]->fHome = true;
  340.                 done = false;
  341.             }
  342.             this->fTheBoids[cnt]->Move(
  343.                                         &dummy,
  344.                                         &this->fFlockRect,
  345.                                         &this->fGoodControls,
  346.                                         this->fComfyDistSquared );
  347.         }
  348.         EndDrawing();
  349.         
  350.     }
  351.     // let everyone see
  352.     Delay(60, &ticks);
  353. }